﻿using MiniFox.Data.Mapping;
using MiniFox.Infrastructure;
using MiniFox.Utility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace MiniFox.Data
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public class ResultSet<TEntity> : IResultSet<TEntity>
    {
        bool _lazyLoad;

        /// <summary>
        /// 
        /// </summary>
        public ResultSet() : this(false)
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="lazyLoad"></param>
        public ResultSet(bool lazyLoad)
        {
            this._lazyLoad = lazyLoad;
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual int RowCount
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual IEnumerable<TEntity> Data
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        public virtual bool LazyLoad
        {
            get
            {
                return _lazyLoad;
            }
        }
        /// <summary>
        /// 创建响应结果对象
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <returns></returns>
        protected virtual ResultObject<TResult> CreateResultObject<TResult>()
        {
            var resultObject = new ResultObject<TResult>(this.RowCount);
            return resultObject;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public virtual ResultObject<IEnumerable<TModel>> GetResultObject<TModel>() where TModel : new()
        {
            var resultObject = CreateResultObject<IEnumerable<TModel>>();
            var modelType = typeof(TModel);

            ITableMapping tableMapping = TableMapping.GetTableMapping(modelType);

            IList<TModel> list = new List<TModel>();
            foreach (var dataItem in this.Data)
            {
                TModel item = new TModel();
                foreach (IColumnMapping colMapping in tableMapping.ColumnMappings)
                {
                    MapEntityToModel(dataItem, item, colMapping);
                }
                list.Add(item);
            }
            resultObject.Result = list;

            return resultObject;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="model"></param>
        /// <param name="colMapping"></param>
        protected virtual void MapEntityToModel<TModel>(TEntity entity, TModel model, IColumnMapping colMapping)
        {
            var entityType = typeof(TEntity);
            var modelType = typeof(TModel);
            var entityProperty = entityType.GetProperty(colMapping.SourceColumn);
            if (entityProperty == null) return;
            var modelProperty = modelType.GetProperty(colMapping.DataSetColumn);
            if (modelProperty == null) return;

            object val = entityProperty.GetValue(entity);
            modelProperty.SetValue(model, val);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="selectFunc"></param>
        /// <returns></returns>
        public virtual ResultObject<IEnumerable<TModel>> GetResultObject<TModel>(Expression<Func<TEntity, TModel>> selectFunc) where TModel : new()
        {
            if (selectFunc == null)
                return this.GetResultObject<TModel>();
            var resultObject = CreateResultObject<IEnumerable<TModel>>();
            resultObject.Result = this.Select(selectFunc);

            return resultObject;
        }
        /// <summary>
        /// 直接以实体类型创建视图表结果
        /// </summary>
        /// <returns></returns>
        public virtual ResultObject<ViewTable> GetTableResultObject()
        {
            var tableMapping = TableMapping.GetTableMapping<TEntity>();
            var viewTable = CreateViewTableSchema(tableMapping);
            this.FillViewTable(viewTable, tableMapping);
            var result = this.CreateResultObject<ViewTable>();
            result.Result = viewTable;
            return result;
            //    var resultObject = CreateResultObject<ViewTable>();
            //    var viewTable = ViewTable.CreateViewTable<TEntity>();
            //    Type type = typeof(TEntity);
            //    foreach (var item in this.Data)
            //    {
            //        var row = viewTable.NewRow();
            //        foreach (var column in viewTable.Columns)
            //        {
            //            var property = type.GetProperty(column.Name);
            //            var val = property.GetValue(item);
            //            row[column.Name] = val;
            //        }
            //        viewTable.Rows.Add(row);
            //    }
            //    resultObject.Result = viewTable;
            //    return resultObject;
        }
        /// <summary>
        /// 根据映射创建视图表结果对象，含行列集
        /// </summary>
        /// <param name="tableMapping"></param>
        /// <returns></returns>
        public virtual ResultObject<ViewTable> GetTableResultObject(ITableMapping tableMapping)
        {
            var viewTable = CreateViewTableSchema(tableMapping);
            this.FillViewTable(viewTable, tableMapping);
            var result = this.CreateResultObject<ViewTable>();
            result.Result = viewTable;
            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="viewTable"></param>
        /// <param name="tableMapping"></param>
        protected virtual void FillViewTable(ViewTable viewTable, ITableMapping tableMapping)
        {
            viewTable.Rows.Clear();
            foreach (var dataItem in this.Data)
            {
                var row = viewTable.NewRow();
                foreach (IColumnMapping colMapping in tableMapping.ColumnMappings)
                {
                    MapDataItemToViewRow(dataItem, row, colMapping);
                }
                viewTable.Rows.Add(row);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataItem"></param>
        /// <param name="row"></param>
        /// <param name="colMapping"></param>
        protected virtual void MapDataItemToViewRow(TEntity dataItem, ViewRow row, IColumnMapping colMapping)
        {
            object val = dataItem.GetValue(colMapping.DataSetColumn);
            row[colMapping.SourceColumn] = val;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="tableMapping"></param>
        /// <returns></returns>
        protected virtual ViewTable CreateViewTableSchema(ITableMapping tableMapping)
        {
            var viewTable = new ViewTable();

            foreach (IColumnMapping colMapping in tableMapping.ColumnMappings)
            {
                var col = new ViewColumn(colMapping.SourceColumn, colMapping.DataSetColumn);
                if (!(colMapping is ColumnMapping column)) continue;
                col.DisplayName = column.DisplayCaption;
                col.IsKey = column.PrimaryKey;
                col.DataType = column.Type.ToString();
                col.Ordinal = column.Ordinal;
                viewTable.Columns.Add(col);
            }
            return viewTable;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="selectFunc"></param>
        /// <returns></returns>
        public virtual IEnumerable<TModel> Select<TModel>(Expression<Func<TEntity, TModel>> selectFunc)
        {
            IEnumerable<TModel> list;
            try
            {
                if (selectFunc == null)
                {
                    throw new InvalidOperationException("无效的操作");
                }
                else
                {

                    if (this.Data is IQueryable<TEntity> data)
                    {
                        if (this.LazyLoad || selectFunc.Body.NodeType == ExpressionType.New)
                        {
                            list = data.Select(selectFunc).ToList();
                        }
                        else
                        {
                            list = data.ToList().Select(selectFunc.Compile());
                        }
                    }
                    else
                    {
                        list = this.Data.Select(selectFunc.Compile());
                    }
                }
            }
            catch
            {
                list = null;
            }

            return list;
        }
    }

}
